package com.gmail.jaredjeya.awesomeplatformer.model.entity.mob;

import com.gmail.jaredjeya.awesomeplatformer.model.Game;
import com.gmail.jaredjeya.awesomeplatformer.model.entity.Entity;
import com.gmail.jaredjeya.awesomeplatformer.model.level.Level;
import com.gmail.jaredjeya.awesomeplatformer.model.sprites.Sprite;

public class Mob extends Entity {

	protected float xVel, yVel;
	protected float xHalfSize, yHalfSize;
	protected boolean canCollide;
	protected boolean touchingGround = false;
	protected boolean isLiving = true;

	public Mob(Sprite sprite, float xPos, float yPos, float xHalfSize, float yHalfSize, boolean collides) {
		super(sprite, xPos, yPos);
		this.xHalfSize = xHalfSize;
		this.yHalfSize = yHalfSize;
		this.canCollide = collides;
	}

	/**
	 * Sets xVel in Tiles/s.
	 * 
	 * @param xVel
	 *            The raw velocity
	 */
	public void setXVelocity(float xVel) {
		this.xVel = xVel / 60F;
	}

	/**
	 * Sets xVel in Tiles/s.
	 * 
	 * @param yVel
	 *            The raw velocity
	 */
	public void setYVelocity(float yVel) {
		this.yVel = yVel / 60F;
	}

	/**
	 * Accelerates the mob by the given floats, measured in Tiles/s^2
	 * 
	 * @param xa
	 * @param ya
	 */
	public void accelerate(float xa, float ya) {
		if (xa != 0F) xVel += xa / 3600F;
		if (ya != 0F) yVel += ya / 3600F;
	}

	/**
	 * Moves by a certain number of tiles, instantly.
	 * 
	 * @param xMove
	 * @param yMove
	 */
	protected void move(float xMove, float yMove, Game game) {
		if (xMove != 0F) xPos += xMove;
		if (yMove != 0F) yPos += yMove;
		if (xPos > game.getCurrentLevel().width - 0.5F) {
			xPos = game.getCurrentLevel().width - 0.5F;
			setXVelocity(-0.001F);
		}
		if (yPos > game.getCurrentLevel().height - 0.5F) {
			yPos = game.getCurrentLevel().height - 0.5F;
			setYVelocity(-0.001F);
		}
		if (xPos < 0.5F) {
			xPos = 0.5F;
			setXVelocity(+0.001F);
		}
		if (yPos < -game.getCurrentLevel().height / 2F) {
			yPos = -game.getCurrentLevel().height / 2F;
			setYVelocity(+0.001F);
			touchingGround = true;
		}
	}

	public void update(Game game) {
		move(xVel, yVel, game);
		
		if (canCollide) {
			checkTileCollisions(game);
			checkEntityCollisions(game);
		}
	}

	protected void checkEntityCollisions(Game game) {
		
	}

	/**
	 * Checks the specified entity against 4 surrounding tiles.
	 * @param game
	 */
	protected void checkTileCollisions(Game game) {
		touchingGround = false;
		boolean tlCol = false, trCol = false, blCol = false, brCol = false;
		Level level = game.getCurrentLevel();
		int yFloor = (int) Math.round(yPos) - 1;
		int xFloor = (int) Math.round(xPos) - 1;
		
		if(level.getTileAt(xFloor, yFloor).isSolid()) tlCol = true;
		if(level.getTileAt(xFloor + 1, yFloor).isSolid()) trCol = true;
		if(level.getTileAt(xFloor, yFloor + 1).isSolid()) blCol = true;
		if(level.getTileAt(xFloor + 1, yFloor + 1).isSolid()) brCol = true;
		
		if(level.getTileAt(xFloor, yFloor).isDamaging()) kill();
		if(level.getTileAt(xFloor + 1, yFloor).isDamaging()) kill();
		if(level.getTileAt(xFloor, yFloor + 1).isDamaging()) kill();
		if(level.getTileAt(xFloor + 1, yFloor + 1).isDamaging()) kill();
		
		//if(tlCol && trCol) {
		//	yPos = yFloor + 1.5F;
		//	yVel = +0.001F;
		//}
		//if(blCol && brCol) {
		//	yPos = yFloor + 0.5F;
		//	yVel = -0.001F;
		//}
		//if(tlCol && blCol) {
		//	xPos = xFloor + 1.5F;
		//	xVel = +0.001F;
		//}
		//if(trCol && brCol) {
		//	xPos = xFloor + 0.5F;
		//	xVel = -0.001F;
		//}
		
		if(tlCol) {
			float m = Math.abs((yPos - yFloor + 0.5F) / (xPos - xFloor + 0.5F));
			if (m >= 1) {
				yPos = yFloor + 1.5F;
				yVel = +0.001F;
			}
			else {
				xPos = xFloor + 1.5F;
				xVel = +0.001F;
			}
		}
		
		if(tlCol) {
			float m = Math.abs((yPos -  (yFloor + 0.5F)) / (xPos - (xFloor + 0.5F)));
			if (m >= 1) {
				yPos = yFloor + 1.5F;
				yVel = +0.001F;
			}
			else {
				xPos = xFloor + 1.5F;
				xVel = +0.001F;
			}
		}
		
		if(trCol) {
			float m = Math.abs((yPos - (yFloor + 0.5F)) / (xPos - (xFloor + 1.5F)));
			if (m >= 1) {
				yPos = yFloor + 1.5F;
				yVel = +0.001F;
			}
			else {
				xPos = xFloor + 0.5F;
				xVel = -0.001F;
			}
		}
		
		if(blCol) {
			float m = Math.abs((yPos - (yFloor + 1.5F)) / (xPos - (xFloor + 0.5F)));
			if (m >= 1) {
				yPos = yFloor + 0.5F;
				yVel = -0.001F;
				touchingGround = true;
			}
			else {
				xPos = xFloor + 1.5F;
				xVel = +0.001F;
			}
		}
		
		if(brCol) {
			float m = Math.abs((yPos - (yFloor + 1.5F)) / (xPos - (xFloor + 1.5F)));
			if (m >= 1) {
				yPos = yFloor + 0.5F;
				yVel = -0.001F;
				touchingGround = true;
			}
			else {
				xPos = xFloor + 0.5F;
				xVel = -0.001F;
			}
		}
	}
	
	protected void kill() {
		this.isLiving = false;
	}

	/**
	 * Checks for collision between the calling object and an AABB defined in
	 * the parameters. This should be used in conjunction with an algorithm to
	 * find the shortest resolution vector, if resolution is needed.
	 * 
	 * @param xCoord
	 *            The x co-ordinate of the centre of the object to check
	 *            against.
	 * @param yCoord
	 *            The x co-ordinate of the centre of the object to check
	 *            against.
	 * @param halfWidth
	 *            The half-width of the object to check against.
	 * @param halfHeight
	 *            The half-height of the object to check against.
	 * @return Whether the objects are colliding.
	 */
	protected boolean collides(float xCoord, float yCoord, float halfWidth, float halfHeight) {
		if (Math.abs(xCoord - xPos) < halfWidth + xHalfSize) {
			if (Math.abs(yCoord - yPos) < halfHeight + yHalfSize) {
				return true;
			}
		}
		return false;
	}
	
	/**
	 * Checks for collision between the calling object and a point.
	 * @param xCoord
	 * @param yCoord
	 * @return Whether the object and the point are colliding.
	 */
	protected boolean inside(float xCoord, float yCoord) {
		if (Math.abs(xCoord - xPos) < xHalfSize) {
			if (Math.abs(yCoord - yPos) < yHalfSize) {
				return true;
			}
		}
		return false;
	}

}
